package com.thunder.ktv.scoreengine2test.ui;

import android.animation.ArgbEvaluator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.thunder.ktv.scoreengine2sdk.ScoreEngine2;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class LyricsView extends SurfaceView implements SurfaceHolder.Callback, Runnable {

    private static final String TAG = "LyricsViewLog";

    // --- 【修改】布局常量 ---
    private static final int DISPLAY_LINE_COUNT = 20;
    private static final float LYRIC_AREA_WIDTH_PERCENT = 0.45f; // 左侧歌词区域占45%
    private static final int SCORE_COLUMN_COUNT = 6;
    private static final String[] SCORE_HEADERS = {"总分", "音高", "亮度", "节奏", "情感", "气息"};
    private static final String LYRIC_HEADER = "歌词";
    private static final String AVG_SCORE_HEADER = "平均分";
    private static final String GOOD_SCORE_HEADER = "高分卡";

    private static final float HEADER_ROW_HEIGHT_DP = 28f;
    private static final float CELL_PADDING_LEFT = 10f; // 分数单元格内边距
    private static final float LYRIC_PADDING_LEFT = 20f; // 歌词区内边距

    // --- 滚动和控制常量 ---
    private static final long AUTO_SCROLL_BACK_DELAY = 2000;
    private static final float SCROLL_SPEED_FACTOR = 0.15f;
    private static final long INFO_DISPLAY_DURATION = 3000;

    // --- 分数颜色配置 ---
    private static final int SCORE_BAD = 60;
    public static final int SCORE_GOOD = 85;
    private static final int COLOR_BAD = Color.WHITE;
    private static final int COLOR_PASS = Color.YELLOW;
    private static final int COLOR_GOOD = Color.RED;

    // --- 绘制相关 ---
    private final Paint mNormalPaint, mCurrentPaint, mHighlightPaint;
    private final Paint mScorePaint, mCurrentScorePaint, mHeaderPaint, mSeparatorPaint;
    private final Paint mStatPaint;
    private final ArgbEvaluator mArgbEvaluator;
    private float mNormalTextSize, mCurrentTextSize, mLineHeight, mHeaderRowHeight, mFixedTopAreaHeight;
    private float mStatTextSize;

    private String mSongName = "", mArtistName = "";
    private final Object mLock = new Object();
    private List<LyricLine> mLyricLines = new ArrayList<>();
    private volatile Thread mDrawThread;
    private volatile boolean mIsRunning = false, mIsPaused = true, mIsUserScrolling = false;
    private long mPlaybackTime = 0, mStartTime = 0, mPauseTimeOffset = 0;
    private int mCurrentLineIndex = 0;
    private float mTargetScrollY = 0, mCurrentScrollY = 0;

    // --- 统计数据 ---
    private final long[] mTotalScores = new long[SCORE_COLUMN_COUNT];
    private final int[] mGoodScoreCounts = new int[SCORE_COLUMN_COUNT];
    private int mScoredLineCount = 0;

    private final GestureDetector mGestureDetector;
    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
    private final Runnable mAutoScrollBackRunnable = () -> mIsUserScrolling = false;

    public LyricsView(Context context, AttributeSet attrs) { this(context, attrs, 0); }
    public LyricsView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mArgbEvaluator = new ArgbEvaluator();
        mNormalTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14, getResources().getDisplayMetrics());
        mCurrentTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 22, getResources().getDisplayMetrics());
        mStatTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics());
        mLineHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25, getResources().getDisplayMetrics());
        mHeaderRowHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, HEADER_ROW_HEIGHT_DP, getResources().getDisplayMetrics());
        mFixedTopAreaHeight = mHeaderRowHeight * 3;

        mNormalPaint = new Paint() {{ setColor(Color.WHITE); setTextSize(mNormalTextSize); setAntiAlias(true); setTextAlign(Paint.Align.LEFT); }};
        mCurrentPaint = new Paint(mNormalPaint) {{ setTextSize(mCurrentTextSize); }};
        mHighlightPaint = new Paint(mCurrentPaint) {{ setColor(Color.RED); }};
        mScorePaint = new Paint(mNormalPaint);
        mCurrentScorePaint = new Paint(mCurrentPaint);
        mHeaderPaint = new Paint(mNormalPaint) {{ setColor(Color.LTGRAY); }};
        mStatPaint = new Paint(mNormalPaint) {{ setTextSize(mStatTextSize); }};
        mSeparatorPaint = new Paint() {{ setColor(Color.DKGRAY); setStrokeWidth(2f); }};

        getHolder().addCallback(this);
        mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                mIsUserScrolling = true;
                mMainHandler.removeCallbacks(mAutoScrollBackRunnable);
                mCurrentScrollY += distanceY;
                float minScrollY = 0;
                float maxScrollY = mLyricLines.isEmpty() ? 0 : (mLyricLines.size() - 1) * mLineHeight;
                mCurrentScrollY = Math.max(minScrollY, Math.min(mCurrentScrollY, maxScrollY));
                return true;
            }
            @Override
            public boolean onDown(MotionEvent e) {
                mIsUserScrolling = true;
                mMainHandler.removeCallbacks(mAutoScrollBackRunnable);
                return true;
            }
        });
    }

    private int getScoreColor(int score) {
        if (score < SCORE_BAD) return COLOR_BAD;
        if (score < SCORE_GOOD) return (int) mArgbEvaluator.evaluate((float) (score - SCORE_BAD) / (SCORE_GOOD - SCORE_BAD), COLOR_BAD, COLOR_PASS);
        return (int) mArgbEvaluator.evaluate(Math.min(1.0f, (float) (score - SCORE_GOOD) / (100 - SCORE_GOOD)), COLOR_PASS, COLOR_GOOD);
    }

    @Override
    public void run() {
        while (mIsRunning) {
            Canvas canvas = null;
            synchronized (mLock) {
                try {
                    canvas = getHolder().lockCanvas();
                    if (canvas != null) {
                        updateState_l();
                        drawCanvas_l(canvas);
                    }
                } finally {
                    if (canvas != null) getHolder().unlockCanvasAndPost(canvas);
                }
            }
            try { Thread.sleep(33); } catch (InterruptedException e) { /* ignored */ }
        }
    }

    private void updateState_l() {
        if (!mIsPaused) {
            mPlaybackTime = (System.currentTimeMillis() - mStartTime) + mPauseTimeOffset;
        }
        mCurrentLineIndex = findCurrentLineIndex_l(mPlaybackTime);

        if (!mIsUserScrolling) {
            mTargetScrollY = mCurrentLineIndex * mLineHeight;
            if (mCurrentScrollY != mTargetScrollY) {
                mCurrentScrollY += (mTargetScrollY - mCurrentScrollY) * SCROLL_SPEED_FACTOR;
                if (Math.abs(mCurrentScrollY - mTargetScrollY) < 1.0f) { mCurrentScrollY = mTargetScrollY; }
            }
        }
    }

    private void drawCanvas_l(Canvas canvas) {
        drawLyrics_l(canvas);
        drawFixedRows_l(canvas);
    }

    // 【重构】绘制固定的三行 (交换布局)
    private void drawFixedRows_l(Canvas canvas) {
        Paint bgPaint = new Paint() {{ setColor(Color.parseColor("#222222")); }};
        canvas.drawRect(0, 0, getWidth(), mFixedTopAreaHeight, bgPaint);

        float separatorX = getWidth() * LYRIC_AREA_WIDTH_PERCENT;
        float scoreAreaWidth = getWidth() - separatorX;
        float scoreColumnWidth = scoreAreaWidth / SCORE_COLUMN_COUNT;

        // --- 第1行：绘制表头 ---
        float headerTextY = mHeaderRowHeight / 2 + mHeaderPaint.getTextSize() / 2;
        // 绘制歌词表头 (左侧)
        mHeaderPaint.setTextAlign(Paint.Align.LEFT);
        canvas.drawText(LYRIC_HEADER, LYRIC_PADDING_LEFT, headerTextY, mHeaderPaint);
        // 绘制分数表头 (右侧)
        for (int i = 0; i < SCORE_COLUMN_COUNT; i++) {
            mHeaderPaint.setTextAlign(Paint.Align.CENTER);
            canvas.drawText(SCORE_HEADERS[i], separatorX + i * scoreColumnWidth + scoreColumnWidth / 2, headerTextY, mHeaderPaint);
        }
        mHeaderPaint.setTextAlign(Paint.Align.LEFT); // 恢复

        // --- 第2行：绘制"平均分"标签和数据 ---
        float avgScoreTextY = mHeaderRowHeight + mHeaderRowHeight / 2 + mStatPaint.getTextSize() / 2;
        // 绘制"平均分"标签 (在歌词区最右侧)
        mHeaderPaint.setTextAlign(Paint.Align.RIGHT);
        canvas.drawText(AVG_SCORE_HEADER, separatorX - LYRIC_PADDING_LEFT, avgScoreTextY, mHeaderPaint);
        mHeaderPaint.setTextAlign(Paint.Align.LEFT); // 恢复
        // 绘制平均分数据 (在分数区)
        for (int i = 0; i < SCORE_COLUMN_COUNT; i++) {
            int avgScore = (mScoredLineCount == 0) ? 0 : (int)(mTotalScores[i] / mScoredLineCount);
            mStatPaint.setColor(getScoreColor(avgScore));
            mStatPaint.setTextAlign(Paint.Align.CENTER);
            canvas.drawText(String.valueOf(avgScore), separatorX + i * scoreColumnWidth + scoreColumnWidth / 2, avgScoreTextY, mStatPaint);
        }
        mStatPaint.setTextAlign(Paint.Align.LEFT);

        // --- 第3行：绘制"高分卡"标签和数据 ---
        float goodScoreTextY = mHeaderRowHeight * 2 + mHeaderRowHeight / 2 + mStatPaint.getTextSize() / 2;
        // 绘制"高分卡"标签 (在歌词区最右侧)
        mHeaderPaint.setTextAlign(Paint.Align.RIGHT);
        canvas.drawText(GOOD_SCORE_HEADER, separatorX - LYRIC_PADDING_LEFT, goodScoreTextY, mHeaderPaint);
        mHeaderPaint.setTextAlign(Paint.Align.LEFT); // 恢复
        // 绘制高分卡数据 (在分数区)
        for (int i = 0; i < SCORE_COLUMN_COUNT; i++) {
            mStatPaint.setColor(COLOR_GOOD);
            mStatPaint.setTextAlign(Paint.Align.CENTER);
            canvas.drawText(String.valueOf(mGoodScoreCounts[i]), separatorX + i * scoreColumnWidth + scoreColumnWidth / 2, goodScoreTextY, mStatPaint);
        }
        mStatPaint.setTextAlign(Paint.Align.LEFT);

        canvas.drawLine(separatorX, 0, separatorX, getHeight(), mSeparatorPaint);
    }

    private void drawLyrics_l(Canvas canvas) {
        canvas.drawColor(0xFF666666);
        if (mLyricLines.isEmpty()) return;

        float drawableHeight = getHeight() - mFixedTopAreaHeight;
        float centerY = mFixedTopAreaHeight + drawableHeight / 2f;

        for (int i = 0; i < mLyricLines.size(); i++) {
            LyricLine line = mLyricLines.get(i);
            float lineY = centerY + (i * mLineHeight - mCurrentScrollY);

            if (lineY < mFixedTopAreaHeight - mLineHeight || lineY > getHeight() + mLineHeight) {
                continue;
            }

            if (i == mCurrentLineIndex && !mIsUserScrolling) {
                drawLineContent_l(canvas, line, lineY, mCurrentScorePaint, mCurrentPaint, mHighlightPaint);
            } else {
                drawLineContent_l(canvas, line, lineY, mScorePaint, mNormalPaint, null);
            }
        }
    }

    // 【重构】绘制行内容 (交换布局)
    private void drawLineContent_l(Canvas canvas, LyricLine line, float y, Paint scorePaint, Paint lyricPaint, Paint highlightPaint) {
        float separatorX = getWidth() * LYRIC_AREA_WIDTH_PERCENT;
        float scoreAreaWidth = getWidth() - separatorX;
        float scoreColumnWidth = scoreAreaWidth / SCORE_COLUMN_COUNT;

        // --- 绘制歌词 (左侧) ---
        if (line.isInfoLine) {
            lyricPaint.setTextAlign(Paint.Align.CENTER);
            canvas.drawText(line.text, separatorX / 2, y, lyricPaint);
            lyricPaint.setTextAlign(Paint.Align.LEFT);
        } else {
            // 绘制基础歌词
            canvas.drawText(line.text, LYRIC_PADDING_LEFT, y, lyricPaint);
            // 绘制高亮部分
            if (highlightPaint != null) {
                float highlightWidth = 0;
                float textWidth = lyricPaint.measureText(line.text);
                if (mPlaybackTime >= line.endTime) {
                    highlightWidth = textWidth;
                } else if (mPlaybackTime >= line.startTime) {
                    float passedWidth = 0;
                    for (Word word : line.words) {
                        if (mPlaybackTime >= word.startTime) {
                            float wordWidth = highlightPaint.measureText(String.valueOf(word.text));
                            if (mPlaybackTime < word.endTime) {
                                highlightWidth = passedWidth + wordWidth * ((mPlaybackTime - word.startTime) / (float) word.duration);
                                break;
                            } else {
                                passedWidth += wordWidth;
                                highlightWidth = passedWidth;
                            }
                        } else {
                            break;
                        }
                    }
                }
                if (highlightWidth > 0) {
                    canvas.save();
                    float startX = LYRIC_PADDING_LEFT;
                    canvas.clipRect(startX, y - mLineHeight, startX + highlightWidth, y + mLineHeight);
                    canvas.drawText(line.text, startX, y, highlightPaint);
                    canvas.restore();
                }
            }
        }

        // --- 绘制分数 (右侧) ---
        if (line.scoreResult != null) {
            int[] scores = {
                    line.scoreResult.overallScore, line.scoreResult.pitchScore,
                    line.scoreResult.brightnessScore, line.scoreResult.rhythmScore,
                    line.scoreResult.emotionScore, line.scoreResult.breathScore
            };
            for (int i = 0; i < SCORE_COLUMN_COUNT; i++) {
                scorePaint.setColor(getScoreColor(scores[i]));
                scorePaint.setTextAlign(Paint.Align.CENTER);
                canvas.drawText(String.valueOf(scores[i]), separatorX + i * scoreColumnWidth + scoreColumnWidth / 2, y, scorePaint);
            }
            scorePaint.setTextAlign(Paint.Align.LEFT); // 恢复
        }
    }

    public void addScoreForLine(int lineIndex, ScoreEngine2.ScoreResult result) {
        if (result == null || !result.isValid()) return;

        synchronized (mLock) {
            int realIndex = getRealIndexFromLyricIndex(lineIndex);
            if (realIndex != -1) {
                LyricLine targetLine = mLyricLines.get(realIndex);
                boolean isFirstTimeScoring = (targetLine.scoreResult == null);

                int[] newScores = {
                        result.overallScore, result.pitchScore, result.brightnessScore,
                        result.rhythmScore, result.emotionScore, result.breathScore
                };

                if (isFirstTimeScoring) {
                    for(int i=0; i < SCORE_COLUMN_COUNT; i++) {
                        mTotalScores[i] += newScores[i];
                        if (newScores[i] >= SCORE_GOOD) {
                            mGoodScoreCounts[i]++;
                        }
                    }
                    mScoredLineCount++;
                } else {
                    int[] oldScores = {
                            targetLine.scoreResult.overallScore, targetLine.scoreResult.pitchScore,
                            targetLine.scoreResult.brightnessScore, targetLine.scoreResult.rhythmScore,
                            targetLine.scoreResult.emotionScore, targetLine.scoreResult.breathScore
                    };
                    for(int i=0; i < SCORE_COLUMN_COUNT; i++) {
                        mTotalScores[i] = mTotalScores[i] - oldScores[i] + newScores[i];

                        boolean oldIsGood = oldScores[i] >= SCORE_GOOD;
                        boolean newIsGood = newScores[i] >= SCORE_GOOD;

                        if (!oldIsGood && newIsGood) {
                            mGoodScoreCounts[i]++;
                        } else if (oldIsGood && !newIsGood) {
                            mGoodScoreCounts[i]--;
                        }
                    }
                }

                targetLine.scoreResult = result;
            }
        }
    }

    public void stop() {
        synchronized(mLock) {
            for (LyricLine line : mLyricLines) {
                line.scoreResult = null;
            }
            Arrays.fill(mTotalScores, 0);
            Arrays.fill(mGoodScoreCounts, 0);
            mScoredLineCount = 0;
        }
    }

    // ... (所有其他方法保持原样)
    private int getRealIndexFromLyricIndex(int lyricIndex) {
        if (lyricIndex < 0) return -1;
        int lyricCounter = 0;
        for (int i = 0; i < mLyricLines.size(); i++) {
            if (!mLyricLines.get(i).isInfoLine) {
                if (lyricCounter == lyricIndex) {
                    return i;
                }
                lyricCounter++;
            }
        }
        return -1;
    }
    private static class LyricLine {
        long startTime, endTime;
        String text;
        List<Word> words = new ArrayList<>();
        boolean isInfoLine = false;
        ScoreEngine2.ScoreResult scoreResult = null;
    }
    private static class Word {
        char text;
        long startTime, duration, endTime;
    }
    @Override
    public void surfaceCreated(SurfaceHolder holder) { mIsRunning = true; mDrawThread = new Thread(this); mDrawThread.start(); }
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { mLineHeight = (height - mFixedTopAreaHeight) / DISPLAY_LINE_COUNT; }
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mIsRunning = false;
        if (mDrawThread != null) {
            boolean retry = true;
            while(retry) {
                try {
                    mDrawThread.join();
                    retry = false;
                } catch (InterruptedException e) { /* try again */ }
            }
        }
    }
    public void setSongName(String songName) { this.mSongName = (songName == null) ? "" : songName; }
    public void setArtistName(String artistName) { this.mArtistName = (artistName == null) ? "" : artistName; }
    public void setLyrics(String lyricsText) {
        synchronized(mLock) {
            stop();
            List<LyricLine> parsedLines = parseLyrics(lyricsText);
            List<LyricLine> allLines = new ArrayList<>();
            long firstLyricStartTime = parsedLines.isEmpty() ? 0 : parsedLines.get(0).startTime;
            long infoStartTime = firstLyricStartTime - INFO_DISPLAY_DURATION;
            if (infoStartTime >= 0) infoStartTime = -INFO_DISPLAY_DURATION;
            if (mArtistName != null && !mArtistName.isEmpty()) {
                LyricLine artistLine = new LyricLine();
                artistLine.text = mArtistName;
                artistLine.startTime = infoStartTime;
                artistLine.endTime = firstLyricStartTime;
                artistLine.isInfoLine = true;
                allLines.add(artistLine);
            }
            if (mSongName != null && !mSongName.isEmpty()) {
                LyricLine songLine = new LyricLine();
                songLine.text = mSongName;
                songLine.startTime = infoStartTime;
                songLine.endTime = firstLyricStartTime;
                songLine.isInfoLine = true;
                allLines.add(songLine);
            }
            allLines.addAll(parsedLines);
            this.mLyricLines = allLines;
        }
    }
    public void start() {
        if(mIsPaused){
            resume();
            return;
        }
        synchronized (mLock) {
            if (mLyricLines.isEmpty()) return;
            mStartTime = System.currentTimeMillis();
            mPauseTimeOffset = 0;
            mPlaybackTime = 0;
            mIsPaused = false;
            mIsUserScrolling = false;
        }
    }
    public void pause() {
        synchronized(mLock) {
            if (!mIsPaused) { mIsPaused = true; mPauseTimeOffset = mPlaybackTime; }
        }
    }
    public void resume() {
        synchronized(mLock) {
            if (mIsPaused) { mIsPaused = false; mStartTime = System.currentTimeMillis(); }
        }
    }
    private int findCurrentLineIndex_l(long time) {
        if (mLyricLines.isEmpty()) return 0;
        int low = 0, high = mLyricLines.size() - 1;
        int result = 0;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            if (mLyricLines.get(mid).startTime > time) { high = mid - 1; }
            else { result = mid; low = mid + 1; }
        }
        return result;
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetector.onTouchEvent(event);
        if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
            mMainHandler.postDelayed(mAutoScrollBackRunnable, AUTO_SCROLL_BACK_DELAY);
        }
        return true;
    }
    private static List<LyricLine> parseLyrics(String lyricsText) {
        List<LyricLine> lines = new ArrayList<>();
        if (lyricsText == null || lyricsText.isEmpty()) { return lines; }
        String[] rawLines = lyricsText.split("\\r?\\n");
        Pattern timePattern = Pattern.compile("\\[(\\d{2}):(\\d{2})\\.(\\d{2,3})]");
        Pattern wordPattern = Pattern.compile("<(\\d+),(\\d+)>");
        for (int i = 0; i < rawLines.length - 1; i++) {
            String textLine = rawLines[i];
            if (textLine == null || !textLine.contains("]")) continue;
            String timeLine = rawLines[i + 1];
            if (timeLine == null || !timeLine.contains("<")) continue;
            Matcher timeMatcher = timePattern.matcher(textLine);
            if (timeMatcher.find()) {
                long minutes = Long.parseLong(timeMatcher.group(1));
                long seconds = Long.parseLong(timeMatcher.group(2));
                long millis = Long.parseLong(timeMatcher.group(3));
                if (timeMatcher.group(3).length() == 2) millis *= 10;
                long startTime = minutes * 60 * 1000 + seconds * 1000 + millis;
                String text = textLine.substring(timeMatcher.end());
                String cleanText = text.replaceAll("\\s", "");
                if (cleanText.isEmpty()) continue;
                LyricLine lyricLine = new LyricLine();
                lyricLine.startTime = startTime;
                lyricLine.text = text;
                Matcher wordMatcher = wordPattern.matcher(timeLine);
                long currentWordStartTime = startTime;
                long totalDuration = 0;
                int charIndex = 0;
                while (wordMatcher.find() && charIndex < cleanText.length()) {
                    int duration = Integer.parseInt(wordMatcher.group(1));
                    Word word = new Word();
                    word.text = cleanText.charAt(charIndex);
                    word.startTime = currentWordStartTime;
                    word.duration = duration;
                    word.endTime = currentWordStartTime + duration;
                    lyricLine.words.add(word);
                    currentWordStartTime += duration;
                    totalDuration += duration;
                    charIndex++;
                }
                lyricLine.endTime = startTime + totalDuration;
                lines.add(lyricLine);
                i++;
            }
        }
        Collections.sort(lines, (o1, o2) -> Long.compare(o1.startTime, o2.startTime));
        return lines;
    }
}